/*
 * Copyright (c) 2002-2003 by OpenSymphony
 * All rights reserved.
 */
package org.jackysoft.workflow;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.jackysoft.entity.AbstractNode;
import org.jackysoft.entity.ActionNode;
import org.jackysoft.entity.ActionsNode;
import org.jackysoft.entity.ConditionNode;
import org.jackysoft.entity.ConditionsNode;
import org.jackysoft.entity.ConditionsResultNode;
import org.jackysoft.entity.ExternalPermissionsNode;
import org.jackysoft.entity.FunctionNode;
import org.jackysoft.entity.GlobalActionsNode;
import org.jackysoft.entity.GlobalConditionsNode;
import org.jackysoft.entity.JoinNode;
import org.jackysoft.entity.OsStep;
import org.jackysoft.entity.OsWorkflowRunner;
import org.jackysoft.entity.PermissionNode;
import org.jackysoft.entity.PostFunctionsNode;
import org.jackysoft.entity.PreFunctionsNode;
import org.jackysoft.entity.RegisterNode;
import org.jackysoft.entity.RegistersNode;
import org.jackysoft.entity.RestrictionNode;
import org.jackysoft.entity.ResultNode;
import org.jackysoft.entity.ResultsNode;
import org.jackysoft.entity.SplitNode;
import org.jackysoft.entity.StepNode;
import org.jackysoft.entity.TriggerFunctionNode;
import org.jackysoft.entity.WorkflowNode;
import org.jackysoft.entity.WorkflowRunner;
import org.jackysoft.entity.nosql.RemindEvent;
import org.jackysoft.nosql.RemindEventType;
import org.jackysoft.service.OsVariableContextService;
import org.jackysoft.service.OsVariableService;
import org.jackysoft.service.OsWorkflowRunnerService;
import org.jackysoft.service.RemindEventService;
import org.jackysoft.service.WorkflowNodeService;
import org.jackysoft.util.WorkflowConstant;
import org.jackysoft.util.WorkflowUtil;
import org.jackysoft.workflow.util.OwnerResolver;
import org.jackysoft.workflow.util.WorkflowResultType;
import org.joda.time.DateTime;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.CollectionUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * Abstract workflow instance that serves as the base for specific
 * implementations, such as EJB or SOAP.
 * 
 * @author <a href="mailto:plightbo@hotmail.com">Pat Lightbody</a>
 * @author Hani Suleiman
 */
public abstract class AbstractWorkflow implements Workflow,
		ApplicationContextAware {
	// ~ Static fields/initializers
	// /////////////////////////////////////////////

	protected static final Log log = LogFactory.getLog(AbstractWorkflow.class);

	// ~ Instance fields
	// ////////////////////////////////////////////////////////
	protected ApplicationContext springContext;

	@Resource
	protected OsWorkflowRunnerService workflowService;

	@Resource
	protected OsVariableService varService;

	protected WorkflowContext context;
	
	@Resource
	private OsVariableContextService varSetService;

	@Resource
	private RemindEventService remindService;
	@Resource
	private WorkflowNodeService nodeService;

	@Resource
	private WorkflowUtil workflowUtil;

	@Resource
	private TypeResolver typeResolver;

	// ~ Constructors
	// ///////////////////////////////////////////////////////////

	public AbstractWorkflow() {

	}

	// ~ Methods
	// ////////////////////////////////////////////////////////////////

	/**
	 * 获得指定工作流实例的可用action
	 * 
	 * @param id
	 *            工作流ID
	 * @param inputs
	 *            传入条件的参数
	 * @return 可用的action数组
	 * @throws IllegalArgumentException
	 *             <dd>如果指定的工作流不存在,或者其描述文件不可用
	 */
	public int[] getAvailableActions(long id, Map<String, Object> inputs)
			throws IllegalArgumentException {
		try {

			WorkflowRunner entry = workflowService.findRunner(id);

			if (entry == null) {
				throw new IllegalArgumentException("No such workflow id " + id);
			}

			if (entry.getState() != WorkflowRunner.ACTIVATED) {
				return new int[0];
			}

			String wfname = entry.getRefname();
			WorkflowNode wf = getWorkflowDescriptor(wfname);

			if (wf == null) {
				throw new IllegalArgumentException("No such workflow "
						+ entry.getRefname());
			}

			List<Integer> lactions = Lists.newArrayList();
			Map<String, Object> transientVars = (inputs == null) ? new HashMap<String,Object>()
					: new HashMap<String, Object>(inputs);
			Collection<OsStep> currentSteps = workflowService.findCurrentSteps(id);

			populateTransientMap(entry, transientVars, wf.getRegisters(),
					new Integer(0), currentSteps);

			// get global actions
			GlobalActionsNode globalActions = wf.getGlobalActions();

			for (ActionNode action : globalActions.getActions()) {
				if (action == null)
					continue;
				RestrictionNode restriction = action.getRestriction();
				ConditionsNode conditions = null;

				transientVars.put("actionId", new Integer(action.getId()));

				if (restriction != null) {
					conditions = restriction.getConditions();
				}

				// todo verify that 0 is the right currentStepId
				GlobalConditionsNode gcn = wf.getGlobalConditions();
				ConditionsNode cn = null;
				if (gcn != null)
					cn = gcn.getConditions();
				if (passesConditions(cn, transientVars, 0)
						&& passesConditions(conditions, transientVars, 0)) {
					lactions.add(action.getId());
				}
			}

			// get normal actions
			for (Iterator<OsStep> iterator = currentSteps.iterator(); iterator
					.hasNext();) {
				OsStep step =iterator.next();
				lactions.addAll(getAvailableActionsForStep(wfname, step,
						transientVars));
			}

			int[] actions = new int[lactions.size()];

			for (int i = 0; i < actions.length; i++) {
				actions[i] = new Integer(lactions.get(i));
			}

			return actions;
		} catch (Exception e) {
			log.error("Error checking available actions", e);

			return new int[0];
		}
	}

	/**
	 * @param Long
	 *            id 工作流实体编号
	 * @return List 当前步骤的编号集合
	 */
	public Collection<OsStep> getCurrentSteps(long id) {

		return workflowService.findCurrentSteps(id);
	}

	/**
	 * @ejb.interface-method
	 */
	@Override
	public int getEntryState(long id) {

		return workflowService.findRunner(id).getState();

	}

	/**
	 * @ejb.interface-method
	 */
	public Collection<OsStep> getHistorySteps(long id) {

		return workflowService.findHistorySteps(id);

	}

	/**
	 * @ejb.interface-method
	 */
	@Override
	public List<String> getSecurityPermissions(long id, Map<String, Object> inputs) {
		try {

			WorkflowRunner entry = workflowService.findRunner(id);
			String wfname = entry.getRefname();
			WorkflowNode wf = Workflow.WORKFLOW_DESCRIPTOR.get();

			Map<String, Object> transientVars = (inputs == null) ? new HashMap<String, Object>()
					: new HashMap<String, Object>(inputs);
			Collection<OsStep> currentSteps = workflowService.findCurrentSteps(id);
			populateTransientMap(entry, transientVars, wf.getRegisters(), null,
					currentSteps);

			List<String> s = new ArrayList<String>();

			for (Iterator<OsStep> interator = currentSteps.iterator(); interator
					.hasNext();) {
				OsStep step = interator.next();

				long stepId = step.getId();

				StepNode xmlStep = nodeService.getStepNode(stepId,wfname);

				ExternalPermissionsNode extSec = xmlStep.getPermissions();

				for (PermissionNode security : extSec.getPermissions()) {
					if (security == null)
						continue;

					// to have the permission, the condition must be met or not
					// specified
					// securities can't have restrictions based on inputs, so
					// it's null
					if (security.getRestriction() != null) {
						if (passesConditions(security.getRestriction()
								.getConditions(), transientVars,
								xmlStep.getId())) {
							s.add(security.getName());
						}
					}
				}
			}

			return s;
		} catch (Exception e) {
			log.error("Error getting security permissions for instance #" + id,
					e);
		}

		return Collections.emptyList();
	}

	/**
	 * Returns a workflow definition object associated with the given name.
	 * 
	 * @param workflowName
	 *            the name of the workflow
	 * @return the object graph that represents a workflow definition
	 * @ejb.interface-method
	 */
	public WorkflowNode getWorkflowDescriptor(String workflowName) {

		return null;
	}

	/**
	 * @ejb.interface-method
	 */
	@Override
	public boolean canInitialize(String workflowName, int initialAction) {
		return canInitialize(workflowName, initialAction, null);
	}

	/**
	 * @ejb.interface-method
	 * @param workflowName
	 *            the name of the workflow to check
	 * @param initialAction
	 *            The initial action to check
	 * @param inputs
	 *            the inputs map
	 * @return true if the workflow can be initialized
	 */
	@Override
	public boolean canInitialize(String workflowName, int initialAction,
			Map<String, Object> inputs) {
		WorkflowRunner mockEntry = new OsWorkflowRunner(workflowName);

		// since no state change happens here, a memory instance is just fine
		Map<String, Object> transientVars = new HashMap<String, Object>();

		if (inputs != null) {
			transientVars.putAll(inputs);
		}

		try {
			populateTransientMap(mockEntry, transientVars, null, new Integer(
					initialAction), new ArrayList<OsStep>());

			return canInitializeWorkflow(workflowName, initialAction,
					transientVars);
		} catch (InvalidActionException e) {
			log.error(e.getMessage());

			return false;
		} catch (WorkflowException e) {
			log.error("Error checking canInitialize", e);

			return false;
		}
	}


	@Override
	public boolean canModifyEntryState(long id, int newState) {	
		
		boolean result = workflowService.canModifyRunnerState(id, newState);		
		return result;
	}

	@Override
	public void changeEntryState(long id, int newState)
			throws WorkflowException {
		workflowService.changeRunnerState(id, newState);		
	}

	@Override
	public void doAction(long id, int actionId, Map<String,Object> inputs,
			Collection<StepOwner> owners) throws WorkflowException {

		WorkflowRunner entry = workflowService.findRunner(id);
		String wfname = entry.getRefname();
		if (entry.getState() != WorkflowRunner.ACTIVATED && entry.getState() != WorkflowRunner.CREATED) {
			return;
		}

		WorkflowNode wf = Workflow.WORKFLOW_DESCRIPTOR.get();

		Collection<OsStep> currentSteps = workflowService.findCurrentSteps(id);
		ActionNode action = null;

		Map<String, Object> transientVars = new HashMap<String, Object>();

		if (inputs != null) {
			transientVars.putAll(inputs);
		}

		populateTransientMap(entry, transientVars, wf.getRegisters(),
				new Integer(actionId), currentSteps);

		boolean validAction = false;

		// check global actions
		GlobalActionsNode gan = nodeService.getGlobalActionsNode(wfname);
		if (gan != null)
			for (ActionNode actionDesc : gan.getActions()) {
				if (validAction)
					break;
				boolean avad = isActionAvailable(action, transientVars, 0);
				if (actionDesc.getId() == actionId && avad) {
					action = actionDesc;
					validAction = true;
					break;
				}
			}

		stepouter: for (Iterator<OsStep> iter = currentSteps.iterator(); !validAction
				&& iter.hasNext();) {

			OsStep step = iter.next();
			StepNode s = nodeService.getStepNode(step.getId(),
					wfname);

			ActionsNode ans = s.getActions();
			if (!validAction && ans != null) {
				for (ActionNode actionDesc : ans.getActions()) {

					boolean avad = isActionAvailable(actionDesc, transientVars,
							s.getId());
					if (actionDesc.getId() == actionId && avad) {
						action = actionDesc;
						validAction = true;
						break stepouter;
					}
				}
			}
		}

		try {
			// this.getNextSteps(id, actionId);

			// NEXTOWNERAVALIABLE
			// transition the workflow, if it wasn't explicitly finished, check
			// for an implicit finish
			/**
			 * currentSteps 的来源来自这个实体的当前步骤
			 * */
			Map<String, Long> istransition = transitionWorkflow(entry,
					currentSteps, wf, action, transientVars, inputs, owners);
			if (istransition.isEmpty()) {
				checkImplicitFinish(action, id);
			}

			Object sender = inputs.get(WorkflowConstant.SENDER.toString());
			String now = DateTime.now().toString("Y-M-d H:m:s");
			long lmd = Long.parseLong(DateTime.now().toString("YMd"));
			Object form = inputs.get(WorkflowConstant.FORM_TITLE.toString());
			Collection<RemindEvent> events = Sets.newHashSet();
			for (Map.Entry<String, Long> ow : istransition.entrySet()) {
				RemindEvent evt = new RemindEvent();
				UUID uid = UUID.randomUUID();
				evt.setId(uid.toString());
				evt.setEventType(RemindEventType.PROCESS);				
				evt.setLastNotificed(lmd);				
				evt.setReceiver(ow.getKey());
				evt.setValid(true);
				evt.setArgs(
						 sender.toString(),
						 now,
						 form.toString(),
						 action.getName(),
						 uid.toString() 
						);
				events.add(evt);
			}
			remindService.save(events);
			remindService.fireEvents(events);
			Object sender_id = inputs.get(WorkflowConstant.SENDER_USERID.toString());
			remindService.expireEvent(RemindEventType.PROCESS, String.valueOf(entry.getId()), sender_id.toString());
		} catch (WorkflowException e) {			
			throw e;
		}
	}

	@Override
	public void executeTriggerFunction(long id, int triggerId)
			throws WorkflowException {

		WorkflowRunner entry = workflowService.findRunner(id);

		String wfname = entry.getRefname();
		if (entry == null) {
			log.warn("Cannot execute trigger #" + triggerId
					+ " on non-existent workflow id#" + id);

			return;
		}

		WorkflowNode wf = Workflow.WORKFLOW_DESCRIPTOR.get();

		Map<String, Object> transientVars = new HashMap<String, Object>();
		populateTransientMap(entry, transientVars, wf.getRegisters(), null,
				workflowService.findCurrentSteps(id));
		TriggerFunctionNode tf = nodeService.getTriggerFunctionNode(triggerId, wfname);
		if (tf != null)
			executeFunction(tf.getFunction(), transientVars);
	}

	@Override
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public long initialize(String workflowName, int initialAction, Map inputs)
			throws InvalidRoleException, InvalidInputException,
			WorkflowException {

		WorkflowNode wf = Workflow.WORKFLOW_DESCRIPTOR.get();
		ActionNode initAct = nodeService.getActionNode(initialAction, workflowName);
       
		StepNode startStep = workflowUtil.getStepNode(workflowName, initAct
				.getResultsNode().getUnconditionalResult().getStep());
		// Entry state is CREATED
		WorkflowRunner entry = workflowService.createRunner(workflowName);
        entry.setStartTime(DateTime.now().getMillis());
        entry.setSendTime(DateTime.now().getMillis());
		// start with a memory property set, but clone it after we have an ID
		Map<String, Object> transientVars = new HashMap<String, Object>();
		String user = null;
		//TODO 获取当前用户
		StepOwner so = new StepOwner();
		so.setOwner(user);
		so.setStepId(String.valueOf(startStep.getId()));
		Collection<StepOwner> cs = new ArrayList<StepOwner>();
		cs.add(so);
		transientVars.put(WorkflowConstant.NEXTOWNER.toString(), cs);
		if (inputs != null) {
			transientVars.putAll(inputs);
		}

		RegistersNode rgns = nodeService.getRegistersNode(workflowName);

		populateTransientMap(entry, transientVars, rgns, initialAction,
				new ArrayList<OsStep>());

		if (!canInitialize(workflowName, initialAction, transientVars)) {
			context.setRollbackOnly();
			throw new InvalidRoleException(
					"You are restricted from initializing this workflow");
		}

		try {
			/**
			 * 由于是第一次初始化,所以,currentsteps集合当然为空
			 * */
			transitionWorkflow(entry,  new ArrayList<OsStep>(), wf, initAct,
					transientVars, inputs, cs);

		} catch (WorkflowException e) {
			context.setRollbackOnly();
			throw e;
		}

		long entryId = entry.getId();

		return entryId;
	}

	protected List<Integer> getAvailableActionsForStep(String wfname,
			OsStep step, Map<String, Object> transientVars)
			throws WorkflowException {
		List<Integer> laction = Lists.newArrayList();
		StepNode s = nodeService.getStepNode(step.getId(),
				wfname);

		if (s == null) {
			log.warn("getAvailableActionsForStep called for non-existent step Id #"
					+ step.getId());

			return laction;
		}

		ActionsNode actions = s.getActions();

		if (actions == null) {
			return laction;
		}

		for (ActionNode action : actions.getActions()) {
			if (action == null)
				continue;
			RestrictionNode restriction = action.getRestriction();
			ConditionsNode conditions = null;

			transientVars.put("actionId", new Integer(action.getId()));

			if (restriction != null) {
				conditions = restriction.getConditions();
			}
			GlobalConditionsNode gcn = nodeService
					.getGlobalConditionsNode(wfname);
			ConditionsNode gconditions = gcn == null ? null : gcn
					.getConditions();
			if (passesConditions(gconditions, new HashMap<String, Object>(
					transientVars), s.getId())
					&& passesConditions(conditions,
							new HashMap<String, Object>(transientVars),
							s.getId())) {
				laction.add(new Integer(action.getId()));
			}
		}

		return laction;
	}

	protected int[] getAvailableAutoActions(long id, Map<String, ?> inputs) {
		try {

			WorkflowRunner entry = workflowService.findRunner(id);

			if (entry == null) {
				throw new IllegalArgumentException("No such workflow id " + id);
			}

			if (entry.getState() != WorkflowRunner.ACTIVATED) {
				log.debug("--> state is " + entry.getState());

				return new int[0];
			}

			String wfname = entry.getRefname();
			WorkflowNode wf = Workflow.WORKFLOW_DESCRIPTOR.get();

			if (wf == null) {
				throw new IllegalArgumentException("No such workflow "
						+ entry.getRefname());
			}

			List<Integer> lact = new ArrayList<Integer>();
			Map<String, Object> transientVars = (inputs == null) ? new HashMap<String, Object>()
					: new HashMap<String, Object>(inputs);
			Collection<OsStep> currentSteps = workflowService.findCurrentSteps(id);

			populateTransientMap(entry, transientVars, wf.getRegisters(),
					new Integer(0), currentSteps);

			// get global actions
			GlobalActionsNode globalActions = wf.getGlobalActions();
			if (globalActions != null)
				for (ActionNode action : globalActions.getActions()) {

					transientVars.put("actionId", new Integer(action.getId()));

					if (action.isAuto()) {
						if (isActionAvailable(action, transientVars, 0)) {
							lact.add(new Integer(action.getId()));
						}
					}
				}

			// get normal actions
			for (Iterator<OsStep> iterator = currentSteps.iterator(); iterator
					.hasNext();) {
				OsStep step = iterator.next();
				lact.addAll(getAvailableAutoActionsForStep(wfname, step,
						transientVars));
			}

			int[] actions = new int[lact.size()];

			for (int i = 0; i < actions.length; i++) {
				actions[i] = new Integer(lact.get(i));
			}

			return actions;
		} catch (Exception e) {
			log.error("Error checking available actions", e);

			return new int[0];
		}
	}

	/**
	 * Get just auto action availables for a step
	 */
	protected List<Integer> getAvailableAutoActionsForStep(String wfname,
			OsStep step, Map<String, Object> transientVars)
			throws WorkflowException {
		List<Integer> lact = new ArrayList<Integer>();
		StepNode s = nodeService.getStepNode(step.getId(),
				wfname);

		if (s == null) {
			log.warn("getAvailableAutoActionsForStep called for non-existent step Id #"
					+ step.getId());

			return lact;
		}

		ActionsNode actions = s.getActions();

		if (actions == null) {
			return lact;
		}

		for (ActionNode action : actions.getActions()) {
			if (action == null)
				continue;

			transientVars.put("actionId", new Integer(action.getId()));

			// check auto
			if (action.isAuto()) {
				if (isActionAvailable(action, transientVars, s.getId())) {
					lact.add(new Integer(action.getId()));
				}
			}
		}

		return lact;
	}

	protected void checkImplicitFinish(ActionNode action, long id)
			throws WorkflowException {

		WorkflowRunner entry = workflowService.findRunner(id);

		String wfname = entry.getRefname();
		Collection<OsStep> currentSteps = workflowService.findCurrentSteps(id);

		boolean isCompleted = true;

		for (Iterator<OsStep>  iterator = currentSteps.iterator(); iterator.hasNext();) {
			OsStep step = iterator.next();
			StepNode stepDes = nodeService.getStepNode(step.getId(), wfname);

			// if at least on current step have an available action
			ActionsNode asn = stepDes.getActions();
			if (asn != null && asn.getActions().size() > 0) {
				isCompleted = false;
			}
		}

		if (isCompleted) {
			completeEntry(action, id, currentSteps, WorkflowRunner.COMPLETED);
		}
	}

	/**
	 * Mark the specified entry as completed, and move all current steps to
	 * history.
	 */
	protected void completeEntry(ActionNode action, long id,
			Collection<OsStep> currentSteps, int state) {
		workflowService.setRunnerState(id, state);

		Iterator<OsStep> i = new ArrayList<OsStep>(currentSteps).iterator();

		while (i.hasNext()) {
			OsStep step = i.next();
			String oldStatus = (action != null) ? action.getResultsNode()
					.getUnconditionalResult().getOldStatus() : "Finished";
			workflowService.markFinished(step.getId(),
					(action != null) ? action.getId() : (-1), DateTime.now().getMillis(),
					oldStatus, context.getCaller());
			workflowService.moveToHistory(step.getId());
		}
	}

	/**
	 * 执行用户所提供的function类的execute方法来执行function的功能
	 * 
	 * @param function
	 *            the function to execute
	 * @param transientVars
	 *            the transientVars given by the end-user
	 * @param ps
	 *            the persistence variables
	 */
	@Resource
	private VariableResolver varResolver;

	protected void executeFunction(FunctionNode function,
			Map<String, Object> transientVars) throws WorkflowException {
		if (function != null) {
			String type = function.getType();

			Map<String, String> args = new HashMap<String, String>(
					function.getArgs());

			for (Iterator<Map.Entry<String, String>> iterator = args.entrySet()
					.iterator(); iterator.hasNext();) {
				Map.Entry<String, String> mapEntry = iterator.next();
				mapEntry.setValue(varResolver.translateVariables(
						mapEntry.getValue(), transientVars,
						varService,
						varSetService).toString());
			}

			FunctionProvider provider = typeResolver.getFunction(type, args);

			if (provider == null) {
				String message = "Could not load FunctionProvider class";
				context.setRollbackOnly();
				throw new WorkflowException(message);
			}

			try {
				provider.execute(transientVars, args, varService);
			} catch (WorkflowException e) {
				context.setRollbackOnly();
				throw e;
			}
		}
	}

	protected boolean passesCondition(ConditionNode conditionDesc,
			Map<String, Object> transientVars, long currentStepId)
			throws WorkflowException {
		String type = conditionDesc.getType();

		Map<String, String> args = new HashMap<String, String>(conditionDesc.getArgs());

		for (Iterator<Entry<String, String>> iterator = args.entrySet().iterator(); iterator.hasNext();) {
			Map.Entry<String, String> mapEntry = iterator.next();
			mapEntry.setValue(varResolver.translateVariables(
					 mapEntry.getValue(), transientVars,
					 varService,
					varSetService).toString());
		}

		if (currentStepId != -1) {
			Object stepId = args.get("stepId");

			if ((stepId != null) && stepId.equals("-1")) {
				args.put("stepId", String.valueOf(currentStepId));
			}
		}

		Condition condition = typeResolver.getCondition(type, args);

		if (condition == null) {
			context.setRollbackOnly();
			throw new WorkflowException("Could not load condition");
		}

		try {
			boolean passed = condition.passesCondition(transientVars, args,
					varService);

			if (conditionDesc.isNegate()) {
				passed = !passed;
			}

			return passed;
		} catch (Exception e) {
			context.setRollbackOnly();

			if (e instanceof WorkflowException) {
				throw (WorkflowException) e;
			}

			throw new WorkflowException(
					"Unknown exception encountered when checking condition "
							+ condition, e);
		}
	}
	
	protected boolean passesConditions(String conditionType,
			Collection<ConditionNode> conditions,
			Map<String, Object> transientVars, long currentStepId)
			throws WorkflowException {
		if ((conditions == null) || (conditions.size() == 0)) {
			return true;
		}

		boolean and = "AND".equals(conditionType);
		boolean or = !and;

		for (Iterator<ConditionNode> iterator = conditions.iterator(); iterator
				.hasNext();) {
			AbstractNode descriptor = iterator.next();
			boolean result;

			if (descriptor instanceof ConditionsNode) {
				ConditionsNode conditionsDescriptor = (ConditionsNode) descriptor;
				result = passesConditions(conditionsDescriptor.getType(),
						conditionsDescriptor.getConditions(), transientVars,
						currentStepId);
			} else {
				result = passesCondition((ConditionNode) descriptor,
						transientVars, currentStepId);
			}

			if (and && !result) {
				return false;
			} else if (or && result) {
				return true;
			}
		}

		if (and) {
			return true;
		} else if (or) {
			return false;
		} else {
			return false;
		}
	}

	protected boolean passesConditions(ConditionsNode descriptor,
			Map<String, Object> transientVars, long currentStepId)
			throws WorkflowException {

		return descriptor == null
				|| passesConditions(descriptor.getType(),
						descriptor.getConditions(), transientVars,
						currentStepId);
	}

	protected void populateTransientMap(WorkflowRunner entry,
			Map<String, Object> transientVars, RegistersNode registers,
			Integer actionId, Collection<OsStep> currentSteps) throws WorkflowException {

		transientVars.put("context", context);
		transientVars.put("entry", entry);

		if (actionId != null) {
			transientVars.put("actionId", actionId);
		}

		transientVars.put("currentSteps", new ArrayList<OsStep>(currentSteps));

		// now talk to the registers for any extra objects needed in scope
		if (registers != null) {
			Collection<RegisterNode> rnds = registers.getRegisters();
			for (RegisterNode register : rnds) {
				if (register == null)
					continue;
				Map<String, String> args = register.getArgs();

				String type = register.getType();

				Register r = typeResolver.getRegister(type, args);

				if (r == null) {
					String message = "Could not load register class";
					context.setRollbackOnly();
					throw new WorkflowException(message);
				}

				try {
					transientVars.put(register.getVariableName(), r
							.registerVariable(context, entry, args,
									varService));
				} catch (Exception e) {
					context.setRollbackOnly();

					if (e instanceof WorkflowException) {
						throw (WorkflowException) e;
					}

					throw new WorkflowException(
							"An unknown exception occured while registering variable using register "
									+ r, e);
				}
			}
		}
	}

	/**
	 * 
	 * @return true if the instance has been explicitly completed is this
	 *         transition, false otherwise
	 * @throws WorkflowException
	 **/
	@Resource VariableResolver variableResolver;
	protected Map<String, Long> transitionWorkflow(WorkflowRunner entry,
			Collection<OsStep> currentSteps, WorkflowNode wf, ActionNode action,
			Map<String, Object> transientVars, Map<String,Object> inputs,
			Collection<StepOwner> owners) throws WorkflowException {
		Map<String, Long> resultStep = Maps.newHashMap();

		// 解析owner

		if (CollectionUtils.isEmpty(owners))
			return Collections.emptyMap();

		OwnerResolver orl = new OwnerResolver(owners,
				variableResolver, transientVars,
				varService,
				varSetService);
		// orl.setOwner(rd, wt);
		OsStep step = getCurrentStep(wf, action.getId(), currentSteps,
				transientVars);

		// we're leaving the current step, so let's execute its post-functions
		// check if we actually have a current step
		String wfname = wf.getRefname();
		if (step != null) {
			StepNode sn = nodeService.getStepNode(step.getId(),wfname);
			PostFunctionsNode pfn = sn.getPostFunction();
			if (pfn != null)
				for (FunctionNode function : pfn.getFunctions()) {
					executeFunction(function, transientVars);
				}
		}

		// preFunctions
		// 执行action的预处理功能
		PreFunctionsNode preFunctions = action.getPreFunctions();
		if (preFunctions != null)
			for (FunctionNode function : preFunctions.getFunctions()) {
				if (function == null)
					continue;
				executeFunction(function, transientVars);
			}

		// check each conditional result
		// 检查这个action的条件结果类型
		Collection<ConditionsResultNode> conditionalResults = action
				.getResultsNode().getConditionalResults();
		PreFunctionsNode extraPreFunctions = null;
		PostFunctionsNode extraPostFunctions = null;
		ResultNode[] theResults = new ResultNode[1];

		// 遍历执行条件函数
		for (ConditionsResultNode conditionalResult : conditionalResults) {
			if (conditionalResults == null)
				continue;
			if (passesConditions(null, conditionalResult.getConditions()
					.getConditions(),
					Collections.unmodifiableMap(transientVars),
					(step != null) ? step.getId() : (-1))) {
				// if (evaluateExpression(conditionalResult.getCondition(),
				// entry, wf.getRegisters(), null, transientVars)) {
				theResults[0] = conditionalResult;
				log.info("转向用户:" + theResults[0].getOwner());
				conditionalResult.getPreFunction();
				extraPreFunctions = conditionalResult.getPreFunction();
				extraPostFunctions = conditionalResult.getPostFunction();

				break;
			}
		}

		// use unconditional-result if a condition hasn't been met
		// 如果条件结果类型的条件没通过,或者没有定义条件结果类型就使用无条件结果类型
		if (theResults[0] == null) {
			theResults[0] = action.getResultsNode().getUnconditionalResult();
			log.info("转向用户:" + theResults[0].getOwner());
			extraPreFunctions = theResults[0].getPreFunction();
			extraPostFunctions = theResults[0].getPostFunction();
		}

		log.info("theResult=" + theResults[0].getStep() + ' '
				+ theResults[0].getStatus());

		if (extraPreFunctions != null) {
			// run any extra pre-functions that haven't been run already
			for (FunctionNode function : extraPreFunctions.getFunctions()) {
				if (function == null)
					continue;
				executeFunction(function, transientVars);
			}
		}

		// go to next step
		// 到下一步去，如果下一步是一个分叉的话，去创建各个步骤！
		// 如果需要会签,那么根据owners的数量创建各个步骤......
		if (theResults[0].getSplit() != 0) {
			log.info("转向用户:" + theResults[0].getOwner());
			// the result is a split request, handle it correctly
			SplitNode splitDesc = workflowUtil.getSplitNode(wfname,
					theResults[0].getSplit());
			boolean team = splitDesc.isTeam();
			Collection<ResultNode> results = splitDesc.getResults();
			List<FunctionNode> splitPreFunctions = Lists.newArrayList();
			List<FunctionNode> splitPostFunctions = Lists.newArrayList();

			// check all results in the split and verify the input against any
			// validators specified
			// also build up all the pre and post functions that should be
			// called.
			for (ResultNode resultDescriptor : results) {
				if (resultDescriptor.getPreFunction() != null)
					splitPreFunctions.addAll(resultDescriptor.getPreFunction()
							.getFunctions());
				if (resultDescriptor.getPostFunction() != null)
					splitPostFunctions.addAll(resultDescriptor
							.getPostFunction().getFunctions());
			}

			// now execute the pre-functions
			for (FunctionNode function : splitPreFunctions) {
				if (function == null)
					continue;
				executeFunction(function, transientVars);
			}

			if (!action.isFinish()) {
				// now make these steps...
				boolean moveFirst = true;

				theResults = new ResultNode[results.size()];

				results.toArray(theResults);
				if (!team) {
					for (Iterator<ResultNode> iterator = results.iterator(); iterator
							.hasNext();) {
						ResultNode resultDescriptor = iterator.next();
						OsStep moveToHistoryStep = null;

						if (moveFirst) {
							moveToHistoryStep = step;
						}

						long[] previousIds = null;

						if (step != null) {
							previousIds = new long[] { step.getId() };
						}
						orl.setOwner(resultDescriptor, WorkflowResultType.正常分支);
						log.info("设置分支用户" + resultDescriptor.getOwner());
						OsStep step_New = createNewCurrentStep(resultDescriptor,
								entry, action.getId(), moveToHistoryStep,
								previousIds, transientVars);

						resultStep.put(resultDescriptor.getOwner(),
								step_New.getId());
						moveFirst = false;
					}
				} else { // end of if (team)
					// 需要动态会签的情况
						
					Iterator<ResultNode> iterator = results.iterator();
					ResultNode resultDescriptor = iterator.next();

					// Integer stepId = resultDescriptor.getStep();
					// 动态创建会签步骤,根据传入的用户数目创建
					// 多个分支
					StringBuilder stepIds = new StringBuilder();
					Map<Integer, String> ownerMap = orl.getOwnerMap();
					for (String ows : ownerMap.values()) {
						OsStep moveToHistoryStep = null;

						if (moveFirst) {
							moveToHistoryStep = step;
						}

						long[] previousIds = null;

						if (step != null) {
							previousIds = new long[] { step.getId() };
						}
						resultDescriptor.setOwner(ows);

						OsStep sp = createNewCurrentStep(resultDescriptor, entry,
								action.getId(), moveToHistoryStep, previousIds,
								transientVars);
						stepIds.append(sp.getId()).append(",");
						resultStep.put(resultDescriptor.getOwner(), sp.getId());
						moveFirst = false;
					}
					
					varService.setVariable(entry.getId(),"teamstep",stepIds.toString());

				}
			}// end of if (!action.isFinish())

			// now execute the post-functions
			for (FunctionNode function : splitPostFunctions) {
				if (function == null)
					continue;
				executeFunction(function, transientVars);
			}
		} else if (theResults[0].getJoin() != 0) {
			log.info("转向用户:" + theResults[0].getOwner());
			// this is a join, finish this step...
			JoinNode joinDesc = workflowUtil.getJoinNode(wfname,
					theResults[0].getJoin());
			workflowService.markFinished(step.getId(), action.getId(),
					DateTime.now().getMillis(), theResults[0].getOldStatus(),
					context.getCaller());
			workflowService.moveToHistory(step.getId());
			// ... now check to see if the expression evaluates
			// (get only current steps that have a result to this join)
			Collection<OsStep> joinSteps = new ArrayList<OsStep>();
			joinSteps.add(step);

			// currentSteps = store.findCurrentSteps(id); // shouldn't need to
			// refresh the list
			for (Iterator<OsStep> iterator = currentSteps.iterator(); iterator
					.hasNext();) {
				OsStep currentStep =iterator.next();
				if (currentStep.getId() != step.getId()) {
					StepNode stepDesc = nodeService.getStepNode(currentStep.getId(), wfname);
					if (stepDesc.resultsInJoin(workflowUtil.getJoinNode(wfname,
							theResults[0].getJoin()))) {
						joinSteps.add(currentStep);
					}
				}
			}

			// we also need to check history steps that were finished before
			// this one
			// that might be part of the join
			Collection<OsStep> historySteps = workflowService.findHistorySteps(entry.getId());

			for (Iterator<OsStep> i = historySteps.iterator(); i.hasNext();) {
				OsStep historyStep =  i.next();

				if (historyStep.getId() != step.getId()) {
					StepNode stepDesc = nodeService.getStepNode(historyStep.getId(), wfname);

					if (stepDesc.resultsInJoin(workflowUtil.getJoinNode(wfname,
							theResults[0].getJoin()))) {
						joinSteps.add(historyStep);
					}
				}
			}

			JoinNode jn = new JoinNode(joinSteps);
			transientVars.put("jn", jn);

			// todo verify that 0 is the right value for currentstep here
			ConditionsNode cns = joinDesc.getConditions();
			if (cns != null
					&& passesConditions(null, cns.getConditions(),
							Collections.unmodifiableMap(transientVars), 0)) {
				// now execute the pre-functions
				ResultNode jrst = joinDesc.getResult();
				if (jrst.getPreFunction() != null)
					for (FunctionNode function : jrst.getPreFunction()
							.getFunctions()) {
						executeFunction(function, transientVars);
					}

				long[] previousIds = new long[joinSteps.size()];
				int i = 1;

				for (Iterator<OsStep> iterator = joinSteps.iterator(); iterator
						.hasNext();) {
					OsStep currentStep = iterator.next();

					if (currentStep.getId() != step.getId()) {
						// if this is already a history step (eg, for all join
						// steps completed prior to this one),
						// we don't move it, since it's already history.
						if (!historySteps.contains(currentStep)) {
							workflowService.moveToHistory(currentStep.getId());
						}

						previousIds[i] = currentStep.getId();
						i++;
					}
				}

				if (!action.isFinish()) {
					// ... now finish this step normally
					previousIds[0] = step.getId();
					theResults[0] = joinDesc.getResult();
					// we pass in null for the current step since we've already
					// moved it to history above

					orl.setOwner(joinDesc.getResult(), WorkflowResultType.正常汇聚);
					log.info("设置汇聚用户:" + joinDesc.getResult().getOwner());
					OsStep sp = createNewCurrentStep(theResults[0], entry,
							action.getId(), null, previousIds, transientVars);
					resultStep.put(joinDesc.getResult().getOwner(), sp.getId());
				}

				// now execute the post-functions
				if (jrst.getPostFunction() != null)
					for (FunctionNode function : jrst.getPostFunction()
							.getFunctions()) {

						executeFunction(function, transientVars);
					}
			}
		} else {
			// normal finish, no splits or joins
			long[] previousIds = null;

			if (step != null) {
				previousIds = new long[] { step.getId() };
			}
			if (!action.isFinish()) {

				orl.setOwner(theResults[0], WorkflowResultType.普通单步);
				log.info("设置普通单步用户" + theResults[0].getOwner());
				OsStep sp = createNewCurrentStep(theResults[0], entry,
						action.getId(), step, previousIds, transientVars);
				resultStep.put(theResults[0].getOwner(), sp.getId());
			}
		}

		// postFunctions (BOTH)
		if (extraPostFunctions != null) {
			for (FunctionNode function : extraPostFunctions.getFunctions()) {

				executeFunction(function, transientVars);
			}
		}

		PostFunctionsNode postFunctions = action.getPostFunctions();

		if (postFunctions != null)
			for (FunctionNode function : postFunctions.getFunctions()) {

				executeFunction(function, transientVars);
			}

		// if executed action was an initial action then workflow is activated
		if (action.isStart() && (entry.getState() != WorkflowRunner.ACTIVATED)) {
			changeEntryState(entry.getId(), WorkflowRunner.ACTIVATED);
		}

		// if it's a finish action, then we halt
		if (action.isFinish()) {
			completeEntry(action, entry.getId(),
					getCurrentSteps(entry.getId()), WorkflowRunner.COMPLETED);
			return Collections.emptyMap();
		}
		// get available autoexec actions
		int[] availableAutoActions = getAvailableAutoActions(entry.getId(),
				inputs);
		// we perform the first autoaction that applies, not all of them.
		if (availableAutoActions.length > 0) {
			doAction(entry.getId(), availableAutoActions[0], inputs, owners);
		}

		return resultStep;
	}

	/**
	 * check if an action is available or not
	 * 
	 * @param action
	 *            The action descriptor
	 * @return true if the action is available
	 */
	private boolean isActionAvailable(ActionNode action,
			Map<String, Object> transientVars, long stepId)
			throws WorkflowException {
		if (action == null) {
			return false;
		}

		String wfname = Workflow.WORKFLOW_NAME.get();
		boolean result = true;

		GlobalConditionsNode gcn = nodeService.getGlobalConditionsNode(wfname);

		if (gcn != null) {
			result &= passesConditions(gcn.getConditions(),
					new HashMap<String, Object>(transientVars), stepId);
			if (!result)
				return false;
		}

		RestrictionNode restriction = action.getRestriction();
		ConditionsNode conditions = null;

		if (restriction != null) {

			conditions = restriction.getConditions();
			if (conditions != null)
				result &= passesConditions(conditions,
						new HashMap<String, Object>(transientVars), stepId);

		}

		return result;
	}

	private OsStep getCurrentStep(WorkflowNode wfDesc, int actionId,
			Collection<OsStep> currentSteps, Map<String, Object> transientVars)
			throws WorkflowException {
		if (currentSteps.size() == 1) {
			return currentSteps.iterator().next();
		}

		String wfname = wfDesc.getRefname();
		for (Iterator<OsStep> iterator = currentSteps.iterator(); iterator.hasNext();) {
			OsStep step =  iterator.next();
			ActionNode action = nodeService.getActionNode(actionId,
					wfname);

			// $AR init
			if (isActionAvailable(action, transientVars, step.getId())) {
				return step;
			}

			// $AR end
		}

		return null;
	}

	private boolean canInitializeWorkflow(String workflowName,
			int initialAction, Map<String, Object> transientVars)
			throws WorkflowException {

		ActionNode actionDescriptor = nodeService.getActionNode(
				initialAction, workflowName);

		if (actionDescriptor == null || !actionDescriptor.isStart()) {
			throw new InvalidActionException("Invalid Initial Action #"
					+ initialAction);
		}

		RestrictionNode restriction = actionDescriptor.getRestriction();
		ConditionsNode conditions = null;

		if (restriction != null) {
			conditions = restriction.getConditions();
		}

		return passesConditions(conditions, new HashMap<String, Object>(
				transientVars), 0);
	}

	private OsStep createNewCurrentStep(ResultNode theResult,
			WorkflowRunner entry, int actionId, OsStep currentStep,
			long[] previousIds, Map<String, Object> transientVars)
			throws WorkflowException {

		try {

			long nextStep = theResult.getStep();

			if (nextStep == -1) {
				if (currentStep != null) {
					nextStep = currentStep.getId();
				} else {
					throw new WorkflowException(
							"Illegal argument: requested new current step same as current step, but current step not specified");
				}
			}

			log.debug("Outcome: stepId=" + nextStep + ", status="
					+ theResult.getStatus() + ", owner=" + theResult.getOwner()
					+ ", actionId=" + actionId + ", currentStep="
					+ ((currentStep != null) ? currentStep.getId() : 0));

			if (previousIds == null) {
				previousIds = new long[0];
			}

			String owner = theResult.getOwner();

			// 优先使用描述文件变量当做下步执行者

			String oldStatus = theResult.getOldStatus();
			oldStatus = varResolver.translateVariables(oldStatus,
					transientVars,
					varService,
					varSetService).toString();

			String status = theResult.getStatus();
			status = varResolver.translateVariables(status, transientVars,
					varService,
					varSetService).toString();

			if (currentStep != null) {
				workflowService.markFinished(currentStep.getId(), actionId, DateTime.now().getMillis(),
						oldStatus, context.getCaller());
				workflowService.moveToHistory(currentStep.getId());
			}

			// construct the start date and optional due date
			DateTime startDate = DateTime.now();
			DateTime dueDate = null;

			//TODO dueDate 暂定为天数，以后再规定其他形式 
			if ((theResult.getDueDate() != null) && (theResult.getDueDate().length() > 0)) {
				int d = 0;
				try{
					d = Integer.valueOf(theResult.getDueDate());
				}catch(NumberFormatException e){
					log.error(theResult.getDueDate()+" is not a number ");
					d = 0;
				}
				if(d>0)	dueDate = startDate.plusDays(d);
			}

			OsStep newStep = workflowService.createCurrentStep(entry.getId(),
					nextStep, actionId, owner, startDate.getMillis(), dueDate.getMillis(), status,
					previousIds);

			transientVars.put("createdStep", newStep);

			if ((previousIds != null) && (previousIds.length == 0)
					&& (currentStep == null)) {
				// At this point, it must be a brand new workflow, so we'll
				// overwrite the empty currentSteps
				// with an array of just this current step
				List<OsStep> currentSteps = new ArrayList<OsStep>();
				currentSteps.add(newStep);
				transientVars.put("currentSteps", new ArrayList<OsStep>(
						currentSteps));
			}

			String wfname = entry.getRefname();
			StepNode step = nodeService.getStepNode(nextStep,
					wfname);

			if (step == null) {
				throw new WorkflowException("[next]step #" + nextStep
						+ " does not exist");
			}

			PreFunctionsNode preFunctions = step.getPreFunctions();

			if (preFunctions != null)
				for (FunctionNode function : preFunctions.getFunctions()) {
					executeFunction(function, transientVars);
				}

			return newStep;
		} catch (WorkflowException e) {
			context.setRollbackOnly();
			throw e;
		}
	}

	// if (getAvailableActions(id, Collections.emptyMap())
	//
	public int[] getCurrentAvailiableActions(long id, Map<String,Object> inputs) {

		try {

			WorkflowRunner entry = workflowService.findRunner(id);

			if (entry == null) {
				throw new IllegalArgumentException("No such workflow id " + id);
			}

			if (entry.getState() != WorkflowRunner.ACTIVATED 
					
					&& entry.getState()!=WorkflowRunner.CREATED) {
				return new int[0];
			}

			String wfname = entry.getRefname();
			WorkflowNode wf = Workflow.WORKFLOW_DESCRIPTOR.get();

			if (wf == null) {
				throw new IllegalArgumentException("No such workflow "
						+ entry.getRefname());
			}

			List<Integer> actionIdList = new ArrayList<Integer>();
			Map<String, Object> transientVars = (inputs == null) ? new HashMap<String, Object>()
					: new HashMap<String, Object>(inputs);
			Collection<OsStep> currentSteps = workflowService.findCurrentSteps(id);

			populateTransientMap(entry, transientVars, wf.getRegisters(),
					new Integer(0), currentSteps);

			// get global actions
			GlobalActionsNode globalActions = wf.getGlobalActions();
			if (globalActions != null)
				for (ActionNode action : globalActions.getActions()) {
					if (action == null)
						continue;

					RestrictionNode restriction = action.getRestriction();
					ConditionsNode conditions = null;

					transientVars.put("actionId", new Integer(action.getId()));

					if (restriction != null) {
						conditions = restriction.getConditions();
					}

					// todo verify that 0 is the right currentStepId
					// 全局条件和本地条件都通过，则可以视action为可用
					GlobalConditionsNode gcn = nodeService
							.getGlobalConditionsNode(wfname);
					boolean rst = true;
					if (gcn != null)
						rst &= passesConditions(gcn.getConditions(),
								transientVars, 0);
					if (rst && passesConditions(conditions, transientVars, 0)) {
						actionIdList.add(new Integer(action.getId()));
					}
				}

			// TODO 获取当前用户;
			String owner = null;
			// get normal actions
			for (Iterator<OsStep> iterator = currentSteps.iterator(); iterator
					.hasNext();) {
				OsStep step =iterator.next();
				if (step.getOwner() != null
						&& step.getOwner().equalsIgnoreCase(owner))
					actionIdList.addAll(getAvailableActionsForStep(wfname,
							step, transientVars));
			}

			int[] actions = new int[actionIdList.size()];

			for (int i = 0; i < actions.length; i++) {
				actions[i] = actionIdList.get(i).intValue();
			}

			return actions;
		} catch (Exception e) {
			log.error("Error checking available actions", e);

			return new int[0];
		}
	}

	/**
	 * @return List&ltActionItem&gt list
	 * @throws WorkflowException
	 * */
	@Override
	public List<ActionItem> getActionItem(long id, Map<String, Object> inputs)
			throws WorkflowException {
		List<ActionItem> actionviews = new ArrayList<ActionItem>();
		int[] actions = this.getCurrentAvailiableActions(id, inputs);		
		for (int action : actions) {
			ActionItem actionview = getActionItemById(action, id, inputs);
			actionviews.add(actionview);
		}
		return actionviews;
	}

	@Override
	public ActionItem getActionItemById(int actionId, long id, Map inputs)
			throws InvalidInputException, WorkflowException {
		String wfname = Workflow.WORKFLOW_NAME.get();

		ActionItem actionview = new ActionItem();
		String stepId = getStepOnAction(actionId);
		actionview.setNextSteps(getNextSteps(wfname, actionId,inputs));
		actionview.setStepId(Integer.valueOf(stepId));
		ActionNode an = nodeService.getActionNode(actionId, wfname);
		actionview.setActionName(an.getName());
		actionview.setActionId(actionId);
		actionview.setWorkflowId(id);
		actionview.setWorkflowName(wfname);
		return actionview;
	}

	private String getStepOnAction(int actionId) {

		WorkflowNode desc = Workflow.WORKFLOW_DESCRIPTOR.get();
		Document doc = desc.document();
		Node act = doc.selectSingleNode(String.format("//action[=%d]",
				actionId));
		Element p = act.getParent();
		p = p.getParent();
		String sid = p.attributeValue("stepId");
		return sid == null ? "0" : sid;
	}

	/**
	 * <dd>后继结果不考虑有条件的 <dd>只考虑无条件结果
	 * 
	 * @return 下一步可能步骤的步骤描述符对象集合
	 * @param workflowId
	 *            工作流编号
	 * @param actionId
	 *            当前活动编号
	 * @param inputs 
	 * @throws WorkflowException
	 ***/
	private Set<StepNode> getNextSteps(String wfname, int actionId, Map<String,Object> inputs)
			throws WorkflowException {
		Set<StepNode> nextSteps = Sets.newHashSet();
		ActionNode adesc = nodeService.getActionNode(actionId,wfname);
	
		ResultsNode result = adesc.getResultsNode();
		ResultNode finalrst = result.getUnconditionalResult();
		Collection<ConditionsResultNode> results = result
				.getConditionalResults();
		ConditionsResultNode cndresult = null;
		if (!CollectionUtils.isEmpty(results)) {
			for (ConditionsResultNode cr : results) {

				Collection<ConditionNode> conds = cr.getConditions()
						.getConditions();
				boolean passed = true;
				for (ConditionNode co : conds) {
					ConditionNode cd = co;					
					passed &= passesCondition(cd,inputs, -1);

				}
				if (passed) {
					cndresult = cr;
					break;
				}
			}
		}

		if (cndresult == null)
			nextSteps.addAll(parseStep(wfname, finalrst,inputs));
		else
			nextSteps.addAll(parseStep(wfname, cndresult,inputs));

		return nextSteps;
	}

	

	private Set<StepNode> parseStep(String wfname, ResultNode results, Map<String,Object> inputs)
			throws WorkflowException {

		Set<StepNode> nextSteps = Sets.newHashSet();
		if (results.getStep() != 0) {
			nextSteps.add(workflowUtil.getStepNode(wfname, results.getStep()));
			return nextSteps;
		} else if (results.getJoin() != 0) {
			JoinNode jdesc = workflowUtil
					.getJoinNode(wfname, results.getJoin());
			Collection<ConditionNode> conds = jdesc.getConditions()
					.getConditions();
			boolean passed = true;
			for (ConditionNode co : conds) {
				ConditionNode cd = co;				
				passed &= passesCondition(cd,inputs, -1);

			}
			if (passed) {
				ResultNode trs = jdesc.getResult();
				nextSteps.add(workflowUtil.getStepNode(wfname, trs.getStep()));
			}
			return nextSteps;
		} else if (results.getSplit() != 0) {
			SplitNode sdesc = workflowUtil.getSplitNode(wfname,
					results.getSplit());
			Collection<ResultNode> trs = sdesc.getResults();
			for (ResultNode rd : trs) {

				nextSteps.add(workflowUtil.getStepNode(wfname, rd.getStep()));
			}
			return nextSteps;
		}
		return nextSteps;
	}

	@Override
	public Workflow configContext() {
		return this;
	}

	@Override
	public String getName(long id) {
		String name = workflowService.findRunner(id).getRefname();
		return name;
	}

	@Override
	public void setApplicationContext(ApplicationContext springContext)
			throws BeansException {
		this.springContext = springContext;

	}

}